package rs.util;

import java.io.File;
import java.util.HashMap;
import java.util.Map;

//TODO 添加立即检查的方法.
/**
 * <p>
 * Description:监控某个文件路径下的变化
 * </p>
 * <strong>重命名文件将视为删除原文件并新增新命名文件.</strong>
 * <p>
 * changelog: v2.0
 * 1. 添加Listener.
 * 2. 增加对文件修改的监视.
 * 3. 基于jdk1.5 简化实现.
 * </p>
 * @author imasmallbird, rocy
 * @version 2.0 $ 2011-04-04 01:18:35
 */
public class FolderMonitor implements Runnable {
	
	public static String IGNORES = ".svn";
	
	public class ListenerAdapter implements Listener{
		public void afterFirstScan() {}
		public void onFileCreated(String absolutePath) {}
		public void onFileDeleted(String absolutePath) {}
		public void onFileModified(String absolutePath) {}
		public void onFolderCreated(String absolutePath) {}
		public void onFolderDeleted(String absolutePath) {}
		public void onFolderModified(String absolutePath) {}
	}

	public interface Listener {
		void onFileCreated(String absolutePath);

		void onFileDeleted(String absolutePath);

		void onFileModified(String absolutePath);

		void onFolderCreated(String absolutePath);

		void onFolderDeleted(String absolutePath);

		void onFolderModified(String absolutePath);
		
		void afterFirstScan();
	}

	/**
	 * 监控的文件路径
	 */
	private String dir;

	/**
	 * 原有文件信息
	 */
	private Map<String, Long> oldDirFileMap = new HashMap<String, Long>();

	/**
	 * 扫描间隔时间以秒为单位
	 */
	private int periodInSecond;

	/**
	 * 回调方法集.
	 */
	private Listener listener;

	private boolean triggerCreatedFirstTime = false;

	/**
	 * 初始化相关数据
	 */
	public FolderMonitor(String dir, int periodInSecond, Listener listener) {
		this.dir = dir;
		this.periodInSecond = periodInSecond;
		this.listener = listener;
	}

	/**
	 * 初始化相关数据
	 */
	public FolderMonitor(String dir, int periodInSecond, Listener listener,
			boolean triggerCreatedFirstTime) {
		this.dir = dir;
		this.periodInSecond = periodInSecond;
		this.listener = listener;
		this.triggerCreatedFirstTime = triggerCreatedFirstTime;
	}

	/**
	 * 得到增加的文件及文件夹,并增加到已有的文件信息中
	 */
	private void checkAddedFile(Map<String, Long> nowDirFileMap) {
		for (String key : nowDirFileMap.keySet()) {
			if (null == oldDirFileMap.get(key)) {
				if (new File(key).isDirectory()) {
					listener.onFolderCreated(key);
				} else {
					listener.onFileCreated(key);
				}
			}
		}
	}

	/**
	 * 得到删除的文件及文件夹,并删除已经不存在的文件信息
	 */
	private void checkDeletedFile(Map<String, Long> nowDirFileMap) {
		for (String key : oldDirFileMap.keySet()) {
			if (null == nowDirFileMap.get(key)) {
				if (new File(key).isDirectory()) {
					listener.onFolderDeleted(key);
				} else {
					listener.onFileDeleted(key);
				}
			}
		}
	}

	/**
	 * 得到删除的文件及文件夹,并删除已经不存在的文件信息
	 */
	private void checkModifiedFile(Map<String, Long> nowDirFileMap) {
		for (String key : oldDirFileMap.keySet()) {
			if ((null != nowDirFileMap.get(key))
					&& (oldDirFileMap.get(key).longValue() != nowDirFileMap
							.get(key))) {
				if (new File(key).isDirectory()) {
					listener.onFolderModified(key);
				} else {
					listener.onFileModified(key);
				}
			}
		}
	}

	/**
	 * 线程的执行。对于修改文件的情况，则视为删除与增加两个操作。
	 */
	public void run() {
		boolean isError = false;
		boolean isFirst = true;
		File file = new File(dir);
		if (!triggerCreatedFirstTime) {
			// 初始化开始监控时的文件路径状态
			totalScan(file, oldDirFileMap);
		}
		// displayNowFile();
		while (!isError) {
			try {
				Map<String, Long> nowDirFileMap = new HashMap<String, Long>();
				totalScan(file, nowDirFileMap);
				// 检查删除的文件及文件夹.
				checkDeletedFile(nowDirFileMap);
				// 检查新增的文件及文件夹.
				checkAddedFile(nowDirFileMap);
				// 检查修改的文件及文件夹.
				checkModifiedFile(nowDirFileMap);

				// 更新文件索引
				oldDirFileMap = nowDirFileMap;
				
				if(isFirst){
					isFirst = false;
					listener.afterFirstScan();
				}

				// 指定时间间间隔后扫描路径
				Thread.sleep(periodInSecond * 1000);
			} catch (InterruptedException e) {
				System.out.println("对指定的文件路径进行监控时产生异常，异常信息为：" + e.getMessage());
				isError = true;
			}
		}
	}

	/**
	 * 递归扫描整个路径
	 * 
	 * @param dir
	 * @param ndir
	 * @param dirFileMap
	 *            存放扫描结果
	 */
	private void totalScan(File file, Map<String, Long> dirFileMap) {
		for (File f : file.listFiles()) {
			if(isIgnored(f)){
				continue;
			}
			dirFileMap.put(f.getAbsolutePath(), f.lastModified());
			if (f.isDirectory()) {// 目录
				totalScan(f, dirFileMap);
			}
		}
	}

	// 展示原有文件
	public void displayNowFile() {
		System.out.println(dir + "路径原有文件目录如下：\n");
		for (String key : oldDirFileMap.keySet()) {
			System.out.println(key);
		}
		System.out.println("========================");
	}
	
	private static boolean isIgnored(File f){
		String fName = f.getName();
		if(IGNORES.contains(fName)){
			return true;
		}
		return false;
	}

	/**
	 * just for test
	 * 
	 * @param args
	 */
	public static void main(String[] args) {
		FolderMonitor dirMonitor = new FolderMonitor("tmp", 5, new Listener() {

			@Override
			public void onFileModified(String fileName) {
				System.out.println("[Modified]: " + fileName);
			}

			@Override
			public void onFileDeleted(String fileName) {
				System.out.println("[Deleted]: " + fileName);
			}

			@Override
			public void onFileCreated(String fileName) {
				System.out.println("[Created]: " + fileName);
			}

			@Override
			public void onFolderCreated(String folderName) {
				System.out.println("[Folder Created]: " + folderName);

			}

			@Override
			public void onFolderDeleted(String folderName) {
				System.out.println("[Folder Deleted]: " + folderName);

			}

			@Override
			public void onFolderModified(String folderName) {
				System.out.println("[Folder Modified]: " + folderName);
			}

			@Override
			public void afterFirstScan() {
				System.out.println("First scan done.");
			}
		}, false);
		dirMonitor.run();
	}
}